package com.example.keshe;

import com.example.keshe.Dao.impl.SaleDaoImpl;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import java.util.concurrent.CompletableFuture;
import javafx.scene.control.Alert;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import static com.example.keshe.util.DruidUtil.getConnection;

/**
 * 控制销售信息管理视图的类。
 */
public class SaleView {
    @FXML
    private Pagination pageTable;  // 分页组件
    private int itemsPerPage = 20;  // 每页显示的数据条数
    // 使用FXML注解将FXML文件中的TableView控件与Java代码中的SaleTable字段进行关联
    @FXML
    private TableView<Sale> saleTable;
    @FXML
    private TableColumn<Sale, String> saleIdCol;
    @FXML
    private TableColumn<Sale, String> clothingIdCol;
    @FXML
    private TableColumn<Sale, String> quantitySoldCol;
    @FXML
    private TableColumn<Sale, String> totalAmountCol;
    @FXML
    private TableColumn<Sale, String> remainingStockCol;
    public TableColumn<Sale, String> saleDateCol;

    // 新增按钮
    public Button addButton;
    public Button deleteButton;
    public Button refreshButton;
    public Button queryTotalAmountButton;
    public Button closeButton;
    public Button queryAllTotalAmountButton;

    // 新增标签
    public Label totalAmountLabel;

    /**
     * 初始化方法，界面加载时调用。
     */
    @FXML
    private void initialize() {
        // 初始化分页控件
        initPagination();
        // 加载销售数据，默认加载第一页
        loadPageData(0);
        // 设置TableView的多选模式
        saleTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    }

    /**
     * 初始化分页控件，设置总页数，并添加页码变化监听器。
     */
    private void initPagination() {
        // 设置分页控件的页数
        pageTable.setPageCount(calculatePageCount());
        // 监听页码变化事件，当页码变化时刷新表格数据
        pageTable.currentPageIndexProperty().addListener((observable, oldValue, newValue) -> {
            // 根据新的页码加载数据
            loadPageData(newValue.intValue());
        });
    }

    /**
     * 计算总页数，基于总记录数和每页显示的条数。
     *
     * @return 计算得到的总页数
     */
    private int calculatePageCount() {
        try {
            try (Connection connection = getConnection()) {
                SaleDaoImpl saleDao = new SaleDaoImpl(connection);
                return (int) Math.ceil((double) saleDao.getTotalRecords() / itemsPerPage);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 加载指定页码的数据到 TableView 中。
     *
     * @param pageIndex 要加载的页码
     */
    private void loadPageData(int pageIndex) {
        try {
            try (Connection connection = getConnection()) {
                SaleDaoImpl saleDao = new SaleDaoImpl(connection);
                // 获取每页数据
                List<Sale> pageData = saleDao.selectByPage(pageIndex + 1, itemsPerPage);
                // 将数据加载到 TableView 中
                updateTableView(pageData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新TableView中的数据。
     *
     * @param saleList 包含销售数据的列表
     */
    private void updateTableView(List<Sale> saleList) {
        // 传入 List 集合，更新 TableView
        saleTable.getItems().setAll(saleList);
        // 为每列设置单元格值工厂，以从销售对象中获取属性值显示。
        saleIdCol.setCellValueFactory(new PropertyValueFactory<>("saleId"));
        clothingIdCol.setCellValueFactory(new PropertyValueFactory<>("clothingId"));
        quantitySoldCol.setCellValueFactory(new PropertyValueFactory<>("quantitySold"));
        totalAmountCol.setCellValueFactory(new PropertyValueFactory<>("totalAmount"));
        remainingStockCol.setCellValueFactory(new PropertyValueFactory<>("remainingStock"));
        saleDateCol.setCellValueFactory(new PropertyValueFactory<>("saleDate"));
    }

    /**
     * 用于显示具有指定标题、内容和类型的警报对话框的方法。
     *
     * @param title     对话框标题
     * @param content   对话框内容
     * @param alertType 警报类型
     */
    private void showAlert(String title, String content, Alert.AlertType alertType) {
        Alert alert = new Alert(alertType);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(content);
        alert.showAndWait();
    }

    /**
     * 异步将 Sale 对象添加到数据库的方法。
     *
     * @param sale 要添加到数据库的 Sale 对象
     * @return 一个CompletableFuture，表示异步操作的结果
     */
    private CompletableFuture<Void> addSaleAsync(Sale sale) {
        try (Connection conn = getConnection()) {
            SaleDaoImpl<Sale> saleDao = new SaleDaoImpl<>(conn);
            return saleDao.addSaleAsync(sale);
        } catch (SQLException e) {
            e.printStackTrace();
            return CompletableFuture.completedFuture(null);
        }
    }

    /**
     * 异步从数据库删除 Sale 对象的方法。
     *
     * @param sale 要从数据库中删除的 Sale 对象
     * @return 一个CompletableFuture，表示异步操作的结果
     */
    private CompletableFuture<Void> deleteSaleAsync(Sale sale) {
        try (Connection conn = getConnection()) {
            SaleDaoImpl<Sale> saleDao = new SaleDaoImpl<>(conn);
            return saleDao.deleteSaleAsync(sale);
        } catch (SQLException e) {
            e.printStackTrace();
            return CompletableFuture.completedFuture(null);
        }
    }

    /**
     * 异步计算指定时间范围内某个服装销售总金额的方法。
     *
     * @param clothingId 服装Id
     * @param startTime  起始时间
     * @param endTime    结束时间
     * @return 一个CompletableFuture，包含计算得到的销售总金额
     */
    private CompletableFuture<String> calculateMoney(String clothingId, String startTime, String endTime) {
        try (Connection conn = getConnection()) {
            SaleDaoImpl<Sale> saleDao = new SaleDaoImpl<>(conn);
            return saleDao.calculateMoney(clothingId, startTime, endTime);
        } catch (SQLException e) {
            e.printStackTrace();
            return CompletableFuture.completedFuture("");
        }
    }

    /**
     * 异步计算指定时间范围内所有服装销售总金额的方法。
     *
     * @param startTime 起始时间
     * @param endTime   结束时间
     * @return 一个CompletableFuture，包含计算得到的销售总金额
     */
    public CompletableFuture<String> calculateAllMoney(String startTime, String endTime) {
        try (Connection conn = getConnection()) {
            SaleDaoImpl<Sale> saleDao = new SaleDaoImpl<>(conn);
            return saleDao.calculateAllMoney(startTime, endTime);
        } catch (SQLException e) {
            e.printStackTrace();
            return CompletableFuture.completedFuture("");
        }
    }

    /**
     * JavaFX 应用程序中“添加销售”按钮的事件处理程序。
     *
     * @param event JavaFX事件对象
     */
    @FXML
    private void addSale(ActionEvent event) {
        // 创建用于组织UI元素的GridPane
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25, 25, 25, 25));
        // 创建文本字段和日期选择器以供用户输入
        TextField saleIdField = new TextField();
        TextField clothingIdField = new TextField();
        TextField quantitySoldField = new TextField();
        DatePicker saleDatePicker = new DatePicker();
        // 将标签和输入字段添加到GridPane
        grid.add(new Label("销售Id"), 0, 0);
        grid.add(saleIdField, 1, 0);
        grid.add(new Label("服装Id:"), 0, 1);
        grid.add(clothingIdField, 1, 1);
        grid.add(new Label("销售数量:"), 0, 2);
        grid.add(quantitySoldField, 1, 2);
        grid.add(new Label("销售日期"), 0, 3);
        grid.add(saleDatePicker, 1, 3);
        // 创建用于收集用户输入的对话框
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.setTitle("添加销售");
        dialog.getDialogPane().setContent(grid);
        // 向对话框添加按钮
        ButtonType addButton = new ButtonType("添加", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(addButton, ButtonType.CANCEL);
        Optional<ButtonType> result = dialog.showAndWait();// 显示对话框并等待用户输入
        // 处理用户输入
        result.ifPresent(buttonType -> {
            if (buttonType == addButton) {
                // 用户点击了“添加”按钮
                // 解析输入并创建 Sale 对象
                Sale saleToAdd = Sale.createPartialSale(
                        saleIdField.getText().trim(),
                        clothingIdField.getText().trim(),
                        quantitySoldField.getText().trim(),
                        saleDatePicker.getValue() != null ? saleDatePicker.getValue().toString() : ""
                );
                CompletableFuture<Void> addSaleFuture = addSaleAsync(saleToAdd);// 异步添加销售记录
                // 异步添加操作完成后，刷新表格视图
                addSaleFuture.thenRun(() -> {
                    loadPageData(pageTable.getCurrentPageIndex());// 刷新表格视图
                });
            }
        });
    }

    /**
     * 删除销售记录的事件处理方法。
     *
     * @param event JavaFX事件对象
     */
    @FXML
    private void deleteSale(ActionEvent event) {
        // 创建GridPane，用于用户输入
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25, 25, 25, 25));
        // 创建文本框
        TextField saleIdField = new TextField();
        TextField clothingIdField = new TextField();
        TextField quantitySoldField = new TextField();
        DatePicker saleDatePicker = new DatePicker();
        // 将文本框添加到GridPane
        grid.add(new Label("销售Id"), 0, 0);
        grid.add(saleIdField, 1, 0);
        grid.add(new Label("服装Id:"), 0, 1);
        grid.add(clothingIdField, 1, 1);
        grid.add(new Label("销售数量:"), 0, 2);
        grid.add(quantitySoldField, 1, 2);
        grid.add(new Label("销售日期"), 0, 3);
        grid.add(saleDatePicker, 1, 3);
        // 创建对话框，用于用户输入
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.setTitle("删除销售");
        dialog.getDialogPane().setContent(grid);
        // 添加按钮
        ButtonType deleteButton = new ButtonType("删除", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(deleteButton, ButtonType.CANCEL);
        Optional<ButtonType> result = dialog.showAndWait();// 显示对话框并等待用户输入
        // 处理用户输入
        result.ifPresent(buttonType -> {
            if (buttonType == deleteButton) {
                // 用户点击了删除按钮
                // 解析输入并创建 Sale 对象
                Sale saleToDelete = Sale.createPartialSale(
                        saleIdField.getText().trim(),
                        clothingIdField.getText().trim(),
                        quantitySoldField.getText().trim(),
                        saleDatePicker.getValue() != null ? saleDatePicker.getValue().toString() : ""
                );
                CompletableFuture<Void> deleteSaleFuture = deleteSaleAsync(saleToDelete);// 异步删除销售记录
                // 当异步删除操作完成后，执行刷新操作
                deleteSaleFuture.thenRun(() -> {
                    loadPageData(pageTable.getCurrentPageIndex());// 刷新表格视图
                });
            }
        });
    }

    /**
     * 查询指定时间范围内某服装销售总金额的事件处理方法。
     *
     * @param event JavaFX事件对象
     */
    @FXML
    private void queryTotalAmount(ActionEvent event) {
        // 创建GridPane，用于用户输入
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25, 25, 25, 25));
        // 创建文本框和日期选择器
        TextField clothingIdField = new TextField();
        DatePicker startDatePicker = new DatePicker();
        DatePicker endDatePicker = new DatePicker();
        // 将文本框和日期选择器添加到GridPane
        grid.add(new Label("服装Id:"), 0, 0);
        grid.add(clothingIdField, 1, 0);
        grid.add(new Label("开始日期:"), 0, 1);
        grid.add(startDatePicker, 1, 1);
        grid.add(new Label("结束日期:"), 0, 2);
        grid.add(endDatePicker, 1, 2);
        // 创建对话框，用于用户输入
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.setTitle("计算总金额");
        dialog.getDialogPane().setContent(grid);
        // 添加按钮
        ButtonType calculateButton = new ButtonType("计算", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(calculateButton, ButtonType.CANCEL);
        Optional<ButtonType> result = dialog.showAndWait();// 显示对话框并等待用户输入
        // 处理用户输入
        result.ifPresent(buttonType -> {
            if (buttonType == calculateButton) {
                // 用户点击了计算按钮
                // 解析用户输入
                String clothingId = clothingIdField.getText().trim();
                String startTime = startDatePicker.getValue() != null ? startDatePicker.getValue().toString() : "";
                String endTime = endDatePicker.getValue() != null ? endDatePicker.getValue().toString() : "";
                // 检查用户输入是否完整
                if (clothingId.isEmpty() || startTime.isEmpty() || endTime.isEmpty()) {
                    showAlert("错误", "请提供完整的服装ID、开始日期和结束日期。", Alert.AlertType.ERROR);
                    return;
                }
                CompletableFuture<String> calculateTotalAmountFuture = calculateMoney(clothingId, startTime, endTime);// 异步计算总金额
                // 处理计算结果和异常
                calculateTotalAmountFuture.thenAcceptAsync(totalAmount -> {
                    Platform.runLater(() -> totalAmountLabel.setText(totalAmount)); // 更新 Label 的文本
                }, Platform::runLater).exceptionally(ex -> {
                    Platform.runLater(() -> showAlert("错误", ex.getMessage(), Alert.AlertType.ERROR));// 处理异常
                    return null;
                });
            }
        });
    }

    /**
     * 查询所有销售项在指定时间范围内的总金额的事件处理方法。
     *
     * @param event JavaFX事件对象
     */
    @FXML
    private void queryAllTotalAmount(ActionEvent event) {
        // 创建 GridPane，用于用户输入
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25, 25, 25, 25));
        // 创建日期选择器
        DatePicker startDatePicker = new DatePicker();
        DatePicker endDatePicker = new DatePicker();
        // 将日期选择器添加到 GridPane
        grid.add(new Label("开始日期:"), 0, 0);
        grid.add(startDatePicker, 1, 0);
        grid.add(new Label("结束日期:"), 0, 1);
        grid.add(endDatePicker, 1, 1);
        // 创建对话框，用于用户输入
        Dialog<ButtonType> dialog = new Dialog<>();
        dialog.setTitle("计算总金额");
        dialog.getDialogPane().setContent(grid);
        // 添加按钮
        ButtonType calculateButton = new ButtonType("计算", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(calculateButton, ButtonType.CANCEL);
        Optional<ButtonType> result = dialog.showAndWait();
        // 处理用户输入
        result.ifPresent(buttonType -> {
            if (buttonType == calculateButton) {
                // 用户点击了计算按钮
                // 解析用户输入
                String startTime = startDatePicker.getValue() != null ? startDatePicker.getValue().toString() : "";
                String endTime = endDatePicker.getValue() != null ? endDatePicker.getValue().toString() : "";
                // 检查用户输入是否完整
                if (startTime.isEmpty() || endTime.isEmpty()) {
                    showAlert("错误", "请提供完整的开始日期和结束日期。", Alert.AlertType.ERROR);
                    return;
                }
                CompletableFuture<String> calculateAllTotalAmountFuture = calculateAllMoney(startTime, endTime);// 异步计算所有销售项总金额
                // 处理计算结果和异常
                calculateAllTotalAmountFuture.thenAcceptAsync(totalAmount -> {
                    Platform.runLater(() -> totalAmountLabel.setText(totalAmount)); // 更新 Label 的文本
                }, Platform::runLater).exceptionally(ex -> {
                    Platform.runLater(() -> showAlert("错误", ex.getMessage(), Alert.AlertType.ERROR));// 处理异常
                    return null;
                });
            }
        });
    }

    /**
     * 刷新表格视图的事件处理方法。
     *
     * @param actionEvent JavaFX事件对象
     */
    public void refreshTable(ActionEvent actionEvent) {
        int currentPageIndex = pageTable.getCurrentPageIndex(); // 获取当前页码
        loadPageData(currentPageIndex); // 重新加载数据到表格
        // 设置 totalAmountLabel 的值
        totalAmountLabel.setText(""); // 使用你希望显示的新的值
    }

    /**
     * 关闭应用程序的事件处理方法。
     *
     * @param actionEvent JavaFX事件对象
     */
    public void closeApp(ActionEvent actionEvent) {
        Scene scene = ((Node) actionEvent.getSource()).getScene(); // 获取当前控件所在的 Scene
        Stage stage = (Stage) scene.getWindow(); // 获取当前窗口并关闭
        stage.hide();
    }

}
